/*->c.ckcarc */



#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <time.h>





#include "h.os"
#include "h.bbc"
#include "h.wimp"



#include "h.def"

#include "h.wos"
#include "h.trans"
#include "h.timex"
#include "h.term"

#include "h.view"
#include "h.batch"
#include "h.ftp"
#include "h.main"

#include "h.file"

#include "h.serial"



#include "ckcdeb.h"                     /* Debug & other symbols */
#include "ckcker.h"                     /* Kermit symbols */
#include "ckcfil.h"                     /* File-related symbols */


#include "ckcdef.h"





/*  C O N O C  --  Output a character to the console terminal  */

int conoc(char c)
{
 ttywrite(c);
 return(1);
}



/*  C O N O L  --  Write a line to the console terminal  */

void conol(char * s)
{
 termstring(s);
}


/*  C O N O L L  --  Output a string followed by CRLF  */

void conoll(char * s)
{
 conol(s);
 termstring("\r\n");
}



/*****************************************************************************/


/* Declarations */

#define MAXNAMLEN 256



FILE *fp[ZNFILS] = {                    /* File pointers */
    NULL, NULL, NULL, NULL, NULL, NULL, NULL };

/* (PWP) external def. of things used in buffered file input and output */

static long iflen = -1;                 /* Input file length */
/* static long oflen = -1;   */         /* Output file length */

static char nambuf[MAXNAMLEN+2];        /* Buffer for a filename */




/*  C H K F N  --  Internal function to verify file number is ok  */

/*
 Returns:
  -1: File number n is out of range
   0: n is in range, but file is not open
   1: n in range and file is open
*/

int chkfn(int n)
{
 switch(n)
 {
  case ZCTERM:
  case ZSTDIO:
  case ZIFILE:
  case ZOFILE:
  case ZDFILE:
  case ZTFILE:
  case ZPFILE:
  case ZSFILE:
  case ZSYSFN:
  case ZRFILE:
  case ZWFILE:
              break;

      default:
              debug(F101,"chkfn: file number out of range","",n);
             /* dprintf(0,"File number out of range - %d\n",n); */
              return(-1);
 }

 return((fp[n]==NULL)?0:1);
}





/* (PWP) buffered character output routine to speed up file IO */

int zoutdump(void)
{
 int x;

 zoutptr=zoutbuffer;                  /* reset buffer pointer in all cases */

 debug(F101,"zoutdump chars","",zoutcnt);

 if(zoutcnt==0)
 {                                    /* nothing to output */
  return(0);
 }
 else
 if(zoutcnt<0)
 {                                    /* unexpected negative argument */
  zoutcnt=0;                          /* reset output buffer count */
  return(-1);                         /* and fail. */
 }

 if(fp[ZOFILE]==stdout)
 {
  for(x=0;x<zoutcnt;x++) ttywrite(zoutbuffer[x]);
  zoutcnt=0;
  return(0);
 }
 else  
 if((x=ftpwrite(zoutbuffer,1,zoutcnt,fp[ZOFILE]))!=NULL)
 {   
  debug(F101,"zoutdump fwrite wrote","",x);
  zoutcnt=0;                              /* reset output buffer count */
  return(0);                              /* things worked OK */
 }                           
 else
 {
  zoutcnt=0;                    /* reset output buffer count */
  x=ftpwriteerror(fp[ZOFILE]);         /* get error code */
  debug(F101,"zoutdump fwrite error","",x);
  return(x ? -1 : 0);             /* return failure if error */
 }
}




/*
 * (PWP) (re)fill the buffered input buffer with data.  All file input
 * should go through this routine, usually by calling the zminchar()
 * macro (in ckcker.h).
 */

int zinfill(void)
{
 zincnt=ftpread(zinbuffer, sizeof(char),INBUFSIZE,fp[ZIFILE]);
 debug(F101,"zinfill fp","",fp[ZIFILE]);
 debug(F101,"zinfill zincnt","",zincnt);
 if(zincnt==0) return(-1); /* end of file */

 zinptr=zinbuffer;    /* set pointer to beginning, (== &zinbuffer[0]) */
 zincnt--;                   /* one less char in buffer */
 return((int)(*zinptr++) & 0377); /* because we return the first */
}





/*  Z C L O S E  --  Close the given file.  */

/*  Returns 0 if arg out of range, 1 if successful, -1 if close failed.  */

int zclose(int n,int errflg)
{
 int x, x2;
 int flags;

 if(chkfn(n)<1) return(0);

 if((n==ZOFILE) && (zoutcnt>0)) x2=zoutdump();
 else                           x2=0;

 x=0;                                             /* Initialize return code */

 if(fp[n]!=stdout)
 {
  if(errflg) flags=FTPCLOSEERROR;
  else       flags=FTPCLOSENULL;

  if(n==ZOFILE) x=ftpclosewrite(fp[n],"",flags);
  else
  if(n==ZIFILE) x=ftpcloseread(fp[n],"",flags);
 }

 fp[n]=NULL;
 iflen=-1;                       /* Invalidate file length */

 if(hcflg) trashbatch(TXBFILE);


 if(x==EOF)                      /* if we got a close error */
      return (-1);
 else if (x2 < 0)                /* or an error flushing the last buffer */
      return (-1);               /* then return an error */
 else
      return (1);
}





/*  Z O P E N I  --  Open an existing file for input. */

int zopeni(int n,char * name)
{
 int bn;

 if(n==ZIFILE || n==ZSTDIO)
 {
  bn=txbatchnext();
  fp[ZIFILE]=ftpopenread(bn,0);
 }
 else return(0); /* fails */

 return((fp[ZIFILE]!=NULL) ? 1 : 0);
 name=NULL;
}






/* when Kermit rx's a file, it will first call this routine to make up name */
/* next it will call zopen, with the *local* filename                       */

void zcreatenewfile(char * lname,char * rname)
{
 FILE * fp;
 int    bn;
 int    flags;

 flags=0;
 fp=ftpopenwrite(rname,&bn,0,0,&flags,NULL);
 strcpy(lname,vtable[RXBFILE][bn].lname);
 ftpclosewrite(fp,"{KM8}",0);  /* Kermit created */
}




/*  Z O P E N O  --  Open a new file for output.  */

int zopeno(int n,char * name,struct zattr * zz,struct filinfo * fcb)
{
 int  bn;
 int  flags;

 if(chkfn(n) != 0) return(0);

 if((n==ZCTERM) || (n == ZSTDIO))          /* Terminal or standard output */
 {  
  fp[ZOFILE]=stdout;
  zoutcnt=0;
  zoutptr=zoutbuffer;
  return(1);
 }

 flags=FTPOPENOVER;
 fp[n]=ftpopenwrite(name,&bn,0,0,&flags,NULL);

 zoutcnt=0;    
 zoutptr=zoutbuffer;

 return((fp[n] != NULL) ? 1 : 0);

 zz=NULL;
 fcb=NULL;
}




/*  Z X P A N D  --  Expand a wildcard string into an array of strings  */
/*
  Returns the number of files that match fn1, with data structures set up
  so that first file (if any) will be returned by the next znext() call.
*/


int zxpand(char * fn)
{
 char   dirname[256];
 char * p;
 int    n;
 fxstat f;
 int    dirend;

 p=leaf(fn);
 if(p==fn) dirend=0;
 else
 {
  strcpy(dirname,fn);
  dirend=p-fn-1;
 }

 dirname[dirend]=0;

 trashbatch(TXBFILE);

 startscan();
 n=0;

 while(nextitem(dirname,&f,p))
 {
  if(f.f.object==1)
  {
   if(dirend) strcat(dirname,".");
   strcat(dirname,f.name);
   addtotxbatch(f.f.type,dirname,0,0);
   dirname[dirend]=0;
   n++;
  }
 }

 return(n);
}



/* called to get name of next file from batch */
/* return 1 if no more */

int zgetnextfilename(char * name)
{
 int bn=txbatchnext();
 if(bn<0) return(1);
 strcpy(name,vtable[TXBFILE][bn].lname);
 return(0);
}







/*  Z S A T T R */

/*
 Fills in a Kermit file attribute structure for the file which is to be sent.
 Returns 0 on success with the structure filled in, or -1 on failure.
 If any string member is null, then it should be ignored.
 If any numeric member is -1, then it should be ignored.
*/


int zsattr(struct zattr * xx)
{
 long k;

 k = iflen % 1024L;                  /* File length in K */
 if (k != 0L) k = 1L;
 xx->lengthk = (iflen / 1024L) + k;
 xx->type.len = 0;                   /* File type can't be filled in here */
 xx->type.val = "";
 if(*nambuf)
 {
 /* xx->date.val=zfcdat(nambuf); */ /* File creation date */
  xx->date.len = strlen(xx->date.val);
 }
 else
 {
  xx->date.len = 0;
  xx->date.val = "";
 }

 xx->creator.len = 0;                /* File creator */
 xx->creator.val = "";
 xx->account.len = 0;                /* File account */
 xx->account.val = "";
 xx->area.len = 0;                   /* File area */
 xx->area.val = "";
 xx->passwd.len = 0;                 /* Area password */
 xx->passwd.val = "";
 xx->blksize = -1L;                  /* File blocksize */
 xx->access.len = 0;                 /* File access */
 xx->access.val = "";
 xx->encoding.len = 0;               /* Transfer syntax */
 xx->encoding.val = 0;
 xx->disp.len = 0;                   /* Disposition upon arrival */
 xx->disp.val = "";
 xx->lprotect.len = 0;               /* Local protection */
 xx->lprotect.val = "";
 xx->gprotect.len = 0;               /* Generic protection */
 xx->gprotect.val = "";
 xx->systemid.len = 2;               /* System ID */
 xx->systemid.val = "U1";
 xx->recfm.len = 0;                  /* Record format */
 xx->recfm.val = "";
 xx->sysparam.len = 0;               /* System-dependent parameters */
 xx->sysparam.val = "";
 xx->length = iflen;                 /* Length */

 return(0);
}





/* Z F C D A T -- Return a string containing the time stamp for a file */

char * zfcdat(char * name)
{  name=NULL;
#ifdef TIMESTAMP
    struct stat buffer;
    struct tm *time_stamp, *localtime();
    static char datbuf[20];

    datbuf[0] = '\0';
    if(stat(name,&buffer) != 0) {
        debug(F110,"zcfdat stat failed",name,0);
        return("");
    }

    time_stamp = localtime(&(buffer.st_mtime));
    if (time_stamp->tm_year < 1900) time_stamp->tm_year += 1900;
    sprintf(datbuf,"%-4.4d%02.2d%02.2d %002.2d:%002.2d:%002.2d",
            time_stamp->tm_year,
            time_stamp->tm_mon + 1,
            time_stamp->tm_mday,
            time_stamp->tm_hour,
            time_stamp->tm_min,
            time_stamp->tm_sec);
    debug(F111,"zcfdat",datbuf,strlen(datbuf));
    return(datbuf);
#else
    return("");
#endif /* timestamp */
}



/* Z S T I M E  --  Set creation date for incoming file */
/*
 Call with:
 f  = pointer to name of existing file.
 yy = pointer to a Kermit file attribute structure in which yy->date.val
      is a date of the form yyyymmdd hh:mm:ss, e.g. 19900208 13:00:00.
 x  = is a function code: 0 means to set the file's creation date as given.
      1 means compare the given date with the file creation date.      
 Returns:
 -1 on any kind of error.
  0 if x is 0 and the file date was set successfully.
  0 if x is 1 and date from attribute structure <= file creation date.
  1 if x is 1 and date from attribute structure > file creation date.
*/

int zstime(char * f,struct zattr * yy, int x)
{
 int r =-1;                 /* return code */
 x=0;yy=NULL;f=NULL;

/*
  It is ifdef'd TIMESTAMP because it may not work on V7. bk@kullmar.se.
*/
#ifdef TIMESTAMP
    long tm;
    int i, n, isleapyear, days, stat(), utime();
                   /*       J  F  M  A   M   J   J   A   S   O   N   D   */
                   /*      31 28 31 30  31  30  31  31  30  31  30  31   */
    static
    int monthdays [13] = {  0,0,31,59,90,120,151,181,212,243,273,304,334 };
    char s[5], *getenv(); 
    extern struct tm *localtime();
    struct stat sb;
#ifdef V7
    struct utimbuf {
      time_t timep[2];          /* New access and modificaton time */
    } tp;
    char *tz;
    long timezone;              /* I don't know if timezone is defined in */
                                /* a h-file. */
#else
    struct utimbuf {
      time_t atime;             /* New access time */
      time_t mtime;             /* New modification time */
    } tp;
#endif

#ifdef ANYBSD
    long timezone;
    static struct timeb tbp;
#endif

    debug(F110,"zstime",f,0);

    if ((yy->date.len == 0)
        || (yy->date.len != 17)
        || (yy->date.val[8] != ' ')
        || (yy->date.val[11] != ':')
        || (yy->date.val[14] != ':') ) {
        debug(F111,"Bad creation date ",yy->date.val,yy->date.len);
        return(-1);
    }
    debug(F111,"zstime date check 1",yy->date.val,yy->date.len);
    for(i = 0; i < 8; i++) {
        if (!isdigit(yy->date.val[i])) {
            debug(F111,"Bad creation date ",yy->date.val,yy->date.len);
            return(-1);
        }
    }
    debug(F111,"zstime date check 2",yy->date.val,yy->date.len);
    i++;

    for (; i < 16; i += 3) {
        if ((!isdigit(yy->date.val[i])) || (!isdigit(yy->date.val[i + 1]))) {
            debug(F111,"Bad creation date ",yy->date.val,yy->date.len);
            return(-1);
        }
    }
    debug(F111,"zstime date check 3",yy->date.val,yy->date.len);

#ifdef ANYBSD
    debug(F100,"ztime BSD calling ftime","",0);
    ftime(&tbp);
    debug(F100,"ztime BSD back from ftime","",0);
    timezone = tbp.timezone * 60L;
    debug(F101,"ztime BSD timezone","",timezone);
#endif

#ifdef UXIII
    tzset();                            /* Set `timezone'. */
#endif

#ifdef V7
    if ((tz = getenv("TZ")) == NULL)
      timezone = 0;             /* UTC/GMT */
    else
      timezone = atoi(&tz[3]);  /* Set 'timezone'. */
    timezone *= 60L;
#endif

    debug(F100,"zstime so far so good","",0);

    s[4] = '\0';
    for (i = 0; i < 4; i++)     /* Fix the year */
      s[i] = yy->date.val[i];

    debug(F110,"zstime year",s,0);

    n = atoi(s);

    debug(F111,"zstime year",s,n);

/* Previous year's leap days. This won't work after year 2100, */
/* I don't care about that! */
    isleapyear = (( n % 4 == 0 && n % 100 !=0) || n % 400 == 0);
    days = ( n - 1970) * 365;
    days += (n - 1968 - 1) / 4 - (n - 1900 - 1) / 100 + (n - 1600 - 1) / 400;

    s[2] = '\0';
                                
    for (i = 4 ; i < 16; i += 2) {
        s[0] = yy->date.val[i];
        s[1] = yy->date.val[i + 1];
        n = atoi(s);
    debug(F110,"zstime entering switch",s,0);
        switch (i) {
          case 4:                       /* MM: month */
            if ((n < 1 ) || ( n > 12)) {
                debug(F111,"Bad creation date ",yy->date.val,yy->date.len);
                return(-1);
            }
            days += monthdays [n];
            if (isleapyear && n > 2)
              ++days;
            continue;

          case 6:                       /* DD: day */
            if ((n < 1 ) || ( n > 31)) {
                debug(F111,"Bad creation date ",yy->date.val,yy->date.len);
                return(-1);
            }
            tm = (days + n - 1) * 24L * 60L * 60L;
            i++;                        /* Skip the space */
            continue;

          case 9:                       /* hh: hour */
            if ((n < 0 ) || ( n > 23)) {
                debug(F111,"Bad creation date ",yy->date.val,yy->date.len);
                return(-1);
            }
            tm += n * 60L * 60L;
            i++;                        /* Skip the colon */
            continue;

          case 12:                      /* mm: minute */
            if ((n < 0 ) || ( n > 59)) {
                debug(F111,"Bad creation date ",yy->date.val,yy->date.len);
                return(-1);
            }
#ifdef ANYBSD
            tm += timezone;             /* Correct for time zone */
#else
            tm += timezone;             /* Correct for time zone */
#endif
            tm += n * 60L;
            i++;                        /* Skip the colon */
            continue;

          case 15:                      /* ss: second */
            if ((n < 0 ) || ( n > 59)) {
                debug(F111,"Bad creation date ",yy->date.val,yy->date.len);
                return(-1);
            }
            tm += n;
        }

        if (localtime(&tm)->tm_isdst)
          tm -= 60L * 60L;              /* Adjust for daylight savings time */
    }

    debug(F111,"Attribute creation date ok ",yy->date.val,yy->date.len);

    if (stat(f,&sb)) {                  /* Get the time for the file */
        debug(F110,"Can't do the stat system call on file:",f,"");
        return(-1);
    }
#ifdef V7
    tp.timep[0] = tm;                   /* Set modif. time to creation date */
    tp.timep[1] = sb.st_atime;          /* Don't change the access time */
#else
    tp.mtime = tm;                      /* Set modif. time to creation date */
    tp.atime = sb.st_atime;             /* Don't change the access time */
#endif  

    switch (x) {                        /* Execute desired function */
      case 0:                           /* Set the creation date of the file */
        if (utime(f,&tp)) {             /* Fix modification time */
            debug(F110,"Can't set modification time for file: ",f,0);
            r = -1;
        } else  {
            debug(F110,"Modification time is set for file: ",f,0);
            r = 0;      
        }
        break;
      case 1:                           /* Compare the dates */
        debug(F111,"zstime compare",f,sb.st_atime);
        debug(F111,"zstime compare","packet",tm);
        if (sb.st_atime < tm) r = 0; else r = 1;
        break;
      default:                          /* Error */
        r = -1;
    }
#endif /* TIMESTAMP */
    return(r);
}





/*  Z R T O L  --  Convert remote filename into local form  */

/*  For UNIX, this means changing uppercase letters to lowercase.  */

void zrtol(char * name,char * name2)
{
 strcpy(name2,name);
}



/*  Z L T O R  --  Local TO Remote */

/*  Convert filename from local format to common (remote) form.  */

void zltor(char * name,char * name2)
{
 int bn=txbatchnext();
 strcpy(name2,vtable[TXBFILE][bn].rname);
 name=NULL;
}    









int chdir(char * dirname)
{
 char string[256];
 sprintf(string,"DIR %s",dirname);
 return(os_cli(string)!=NULL);
}



/*  Z C H D I R  --  Change directory  */
/*  return 1 on success 0 on failure   */

int zchdir(char * dirnam)
{
 char *hd;

 if(*dirnam == '\0') hd = "&"; /* should be home dir */
 else hd=dirnam;

 return((chdir(hd)==0)?1:0);
}






/*  Z G T D I R  --  Return pointer to user's current directory  */

char * zgtdir(void)
{
 os_gbpbstr  gpblock;
 static      char currentdir[32];
 os_error *  errpoi;
 char        string[132];
 int         i;

 strcpy(currentdir,transtoken("KM9")); /* Directory is: */

 gpblock.action=6;
 gpblock.data_addr=string;
 errpoi=os_gbpb(&gpblock);
 i=*(string+1);
 (*(string+i+2))=0;

 strcat(currentdir,string+2);

 return(currentdir);
}



/*  Z D E L E T  --  Delete the named file.  */

int zdelet(char * name)
{
 return(remove(name));
}




/*  Z X C M D -- Run a system command so its output can be read like a file */

int zxcmd(int filnum,char * command)
{
 char tempname[256];
 char string[256];

 if(chkfn(filnum)<0) return(-1);  
/* if(filnum==ZSTDIO || filnum==ZCTERM) return(0); */

 trashbatch(TXBFILE);

 /* generate temp file, do command to it */

 if(strlen(path(TXBP))==0) return(0);

 makefilename("KermitCmd",tempname,path(TXBP),0);

 sprintf(string,"%s { > %s }",command,tempname);

 os_cli(string);

 setftype(tempname,TEXT);
 addtotxbatch(TEXT,tempname,1,0);

 return(1); /* OK */
}







/*  Z C H K I  --  Check if input file exists and is readable  */

/*
  Returns:
   >= 0 if the file can be read (returns the size).
     -1 if file doesn't exist or can't be accessed,
     -2 if file exists but is not readable (e.g. a directory file).
     -3 if file exists but protected against read access.
*/


long zchki(char * name)
{
 fstat f;

 if(stat(name,&f)) return(-1);
 else
 if(f.object==2)   return(-2);
 else
                   return(f.length);
}




/* needed for CKCPKT too */

#ifdef DEBUG


/*  Z S O U T  --  Write a string out to the given file, buffered.  */

int zsout(int n,char * s)
{
 if(chkfn(n)<1) return(-1); /* Keep this here, prevents memory faults */
 fputs(s,fp[n]);
 return(0);
}


#endif


#ifdef DEBUG

/*  Z S O U T L  --  Write string to file, with line terminator, buffered  */

int zsoutl(int n,char * s)
{
 /* if (chkfn(n) < 1) return(-1); */
 fputs(s,fp[n]);
 fputs("\n",fp[n]);
 return(0);
}

#endif





/*  Z K S E L F  --  Kill Self: log out own job, if possible.  */

/* Note, should get current pid, but if your system doesn't have */
/* getppid(), then just kill(0,9)...  */

int zkself(void)
{                              /* For "bye", but no guarantee! */
 terminate();
 return(1);
}


/*****************************************************************************/


#ifdef NEVER

static time_t tcount;


/*  R T I M E R --  Reset elapsed time counter  */

void rtimer(void)
{
 tcount=time((time_t *)0);
}


/*  G T I M E R --  Get current value of elapsed time counter in seconds  */


int gtimer(void)
{
 int x;
 x = (int) (time( (time_t *) 0 ) - tcount);
 return( (x < 0) ? 0 : x );
}


/*  Z T I M E  --  Return date/time string  */

void ztime(char ** s)
{
 struct tm *tp;
 time_t timer;

 time(&timer);
 tp=localtime(&timer);
 *s=asctime(tp);
}

#endif

/*****************************************************************************/



/*  T T I N L  --  Read a record (up to break character) from comm line.  */
/*
  Reads up to "max" characters from the communication line, terminating on
  the packet-end character (eol), or timing out and returning -1 if the eol
  character not encountered within "timo" seconds.  The characters that were
  input are copied into "dest" with their parity bits stripped if parity was
  selected.  Returns the number of characters read.  Characters after the
  eol are available upon the next call to this function.

  The idea is to minimize the number of system calls per packet, and also to
  minimize timeouts.  This function is the inner loop of the program and must
  be as efficient as possible.  The current strategy is to use myread().

  Note: this function should be changed to discard interpacket characters,
  rather than store them in the destination buffer.  But as the calling
  conventions are structured, this can't be done because this function does
  not know the packet start character.  All ck*tio.c modules would have to
  be recoded to accept the packet start character as a parameter.
*/



#define CTRLC '\03'



int ttinl(CHAR * dest,int max,int timo,CHAR eol)
{
 int i, m, n, ch;               /* local variables */
 int x, ccn;

 ccn = 0;                            /* Control-C counter */
 x = 0;                              /* Return code */
 m = (parity) ? 0177 : 0377;         /* Parity stripping mask. */
 *dest = '\0';                       /* Clear destination buffer */


 if(timo<0) timo = 0;                /* Safety */

 i=0;           /* Destination index */

      
 timo=timo*100+clock();
 ftp_cont=1;

 while(clock()<timo && ftp_cont)
 {
  if((ch=ftpgetbyte(0))!=-1)
  {
   n=ch;

   if((dest[i++]=(n & m))== eol)
   {
    debug(F101,"ttinl got eol","",eol);
    dest[i] = '\0';         /* Yes, terminate the string, */
    return(i);
   }
   else 
   if((n & 0177) == CTRLC)
   { /* Check for ^C^C */
    if(++ccn>1)
    {        /* If we got 2 in a row, bail out. */
     return(-2);
    }
   }
   else
    ccn = 0;             /* Not ^C, so reset ^C counter, */
  }

  if(i==max)
  {
   x=-1;
   break;
  }
 }

 debug(F100,"ttinl timout","",0);    /* Get here on timeout. */
 debug(F111," with",dest,i);

 return(-1);                          /* and return error code. */
}





/*  T T O L  --  Similar to "ttinl", but for writing.  */

int ttol(char * s,int n)
{
 int x=0;
 for(x=0;x<n;x++) outbyte(*s++);
 return(x);
}


void ttoutline(char * s)
{
 ttol(s,strlen(s));
}



/*  T T F L U I  --  Flush tty input buffer */

int ttflui(void)
{
 ftpflushinput();
 return(0);
}




/*  T T C H K  --  Tell how many characters are waiting in tty input buffer  */

/*  Some callers of this want to know whether there is something to read
 *  either in the system buffers or in our private buffers (and mostly don't
 *  care how many characters, just whether it's more than zero or not), while
 *  some others would be better off with the number of characters in our
 *  private buffers only.
 *
 *  Some systems can say how many characters there are in the system buffers.
 *  Others can not. For those that can't, the number in the private buffers
 *  will have to do (or should we put the tty into O_NDELAY-mode and try to
 *  read one character?). If the system can tell whether there is zero or
 *  more than zero characters, we can return 1 in the latter case even if the
 *  private buffer is empty. (That is good for sliding windows.)
 */


int ttchk(void)
{
 return(ftpinputchars());
}



void sleep(int times)
{
 times=clock()+times*100;
 ftp_cont=1;
 while(clock()<times && ftp_cont) pollzt();
}


/* char * checknames[3]={"1 6Chk","2 12Chk","3 16CRC"}; */

char * checknames[3]={"{KM5}","{KM6}","{KM7}"};

void zsetmode(int bctu)
{
 ftpsetmode(checknames[bctu-1]);
}


/*****************************************************************************/

/*

void tstats(void)
{
}

void fstats(void)
{
}

*/



int xitsta;
int success;



char * DIRCMD="cat ";
char * DELCMD="delete ";
char * TYPCMD="type ";
char * SPACM2="free ";
char * SPACMD="free ";



void ermsg(char * message)
{
 if(tranboxopen) ftpinfo(message);
 else            conoll(message);
}


#ifdef NEVER

void intmsg(int n)
{
 n=0;
}

#endif

void sdebu(int n)
{
 n=0;

}



void rdebu(int n)
{
 n=0;

}



char optbuf[4];  /* Options for MAIL or REMOTE PRINT */


/* return <0 to quit */

int chkint(void)
{
 if(!ftp_ok) return(-1);
 else        return(0);
}





#ifdef SCREEN




/*  S C R E E N  --  Screen display function  */

/*  screen(f,c,n,s)
      f - argument descriptor
      c - a character or small integer
      n - a long integer
      s - a string.
 Fill in this routine with the appropriate display update for the system.
 This version is for a dumb tty.

*/



void screen(int f,char c,long n,char * s)
{
 static int p = 0;                   /* Screen position */
 int len;                            /* Length of string */
 char buf[80];                       /* Output buffer */
 len = strlen(s);                    /* Length of string */


 switch(f)
 {


#ifdef NEVER

  case SCR_FN:                            /* filename */
              conoll("");
              conol(s);
              conoc(SP);
              p=len+1;
              return;
                                                                                  case SCR_AN:                            /* as-name */
              if(p+len > 75)
              {
               conoll("");
               p=0;
              }
              conol("=> ");
              conol(s);
              if((p += (len + 3)) > 78)
              {
               conoll("");
               p = 0;
              }
              return;

  case SCR_FS:                            /* file-size */
              sprintf(buf,", Size: %ld",n);
              conoll(buf);
              p=0;
              return;

#endif
                                                                                
  case SCR_XD:                            /* x-packet data */
              conoll("");
              conoll(s);
              p=0;
              return;
    
  case SCR_ST:                            /* File status */
              switch(c)
              {
               case ST_OK:                     /*  Transferred OK */
                          ftpinfo("{KM0}"); /*Transfer complete*/
                          return;

             case ST_DISC:                   /*  Discarded */
                          ftpinfo("{KM1}"); /* Discarded */
                          return;

              case ST_INT:                    /*  Interrupted */
                          ftpinfo("{KM2}");/*Interrupted*/
                          return;


#ifdef NEVER
             case ST_SKIP:                   /*  Skipped */
                          conoll("");
                          conol("{KM3}"); /* Skipping */
                          conoll(s); p = 0;
                          return;
#endif


              case ST_ERR:
                          ftpinfo("{KM4} %s",s);
                          return;

              }
              break;



#ifdef NEVER



  case SCR_PN:                            /* Packet number */
              sprintf(buf,"%s: %ld",s,n);
              conol(buf);
              p+=strlen(buf);
              return;




  case SCR_PT:                            /* Packet type or pseudotype */
              if(c == 'Y') return;               /* Don't bother with ACKs */
              if (c == 'D')
              {                     /* Only show every 4th data packet */
               if (n % 4) return;
               c = '.';
              }
              if (p++ > 78)
              {                     /* If near right margin, */
               conoll("");                     /* Start new line */
               p = 0;                          /* and reset counter. */
              }
              conoc(c);                           /* Display the character. */
              return;

#endif



  case SCR_EM:                            /* Error message */
              if(tranboxopen)
              {
               ftpinfo(s);
              }
              else
              {
               conoll("");
               conoc('?');
               conoll(s);
               p=0;
              }
              return;           /* +1   */
              
    

#ifdef NEVER



  case SCR_WM:                            /* Warning message */
              conoll("");
              conoll(s);
              p = 0;
              return;




  case SCR_TU:                            /* Undelimited text */
              if((p += len) > 78)
              {
               conoll("");
               p = len;
              }
              conol(s);
              return;





  case SCR_TN:                            /* Text delimited at beginning */
              conoll("");
              conol(s);
              p = len;
              return;





  case SCR_TZ:                            /* Text delimited at end */
              if((p += len) > 78)
              {
               conoll("");
               p = len;
              }
              conoll(s);
              return;




  case SCR_QE:                            /* Quantity equals */
              sprintf(buf,"%s: %ld",s,n);
              conoll(buf);
              p = 0;
              return;

#endif

 }
}



#endif





/*****************************************************************************/

/*  D E B U G  --  Enter a record in the debugging log  */

/*
 Call with a format, two strings, and a number:
   f  - Format, a bit string in range 0-7.
        If bit x is on, then argument number x is printed.
   s1 - String, argument number 1.  If selected, printed as is.
   s2 - String, argument number 2.  If selected, printed in brackets.
   n  - Int, argument 3.  If selected, printed preceded by equals sign.

   f=0 is special: print s1,s2, and interpret n as a char.

*/

#define DBUFL 1024


#ifdef DEBUG


int debug(int f,char * s1,char * s2,int n)
{
 static char s[DBUFL];
 char *sp = s;
 static FILE * dfp=NULL;

 if(!dfp) dfp=fopen("xx","wb");

    switch (f) {
        case F000:                      /* 0, print both strings, */
            if (strlen(s1) + strlen(s2) + 5 > DBUFL) { /* and n as a char */
                sprintf(sp,"DEBUG string too long\n");
            } else {
                if (n > 31 && n < 127)
                  sprintf(sp,"%s%s:%c\n",s1,s2,n);
                else if (n < 32 || n == 127)
                  sprintf(sp,"%s%s:^%c\n",s1,s2,(n+64) & 0x7F);
                else if (n > 127 && n < 160)
                  sprintf(sp,"%s%s:~^%c\n",s1,s2,(n-64) & 0x7F);
                else if (n > 159 && n < 256)
                  sprintf(sp,"%s%s:~%c\n",s1,s2,n & 0x7F);
                else sprintf(sp,"%s%s:%d\n",s1,s2,n);
            }
         /*   puts(s); */
            break;
        case F001:                      /* 1, "=n" */
            sprintf(sp,"=%d\n",n);
        /*    puts(s); */
            break;
        case F010:                      /* 2, "[s2]" */
            if (strlen(s2) + 4 > DBUFL)
              sprintf(sp,"DEBUG string too long\n");
            else sprintf(sp,"[%s]\n",s2);
        /*    puts(""); */
            break;
        case F011:                      /* 3, "[s2]=n" */
            if (strlen(s2) + 15 > DBUFL)
              sprintf(sp,"DEBUG string too long\n");
            else sprintf(sp,"[%s]=%d\n",s2,n);
        /*    puts(s); */
            break;
        case F100:                      /* 4, "s1" */
        /*    puts(s1);  */
            break;
        case F101:                      /* 5, "s1=n" */
            if (strlen(s1) + 15 > DBUFL)
              sprintf(sp,"DEBUG string too long\n");
            else sprintf(sp,"%s=%d\n",s1,n);
        /*    puts(s); */
            break;
        case F110:                      /* 6, "s1[s2]" */
            if (strlen(s1) + strlen(s2) + 4 > DBUFL)
              sprintf(sp,"DEBUG string too long\n");
            else sprintf(sp,"%s[%s]\n",s1,s2);
        /*    puts(s); */
            break;
        case F111:                      /* 7, "s1[s2]=n" */
            if (strlen(s1) + strlen(s2) + 15 > DBUFL)
              sprintf(sp,"DEBUG string too long\n");
            else sprintf(sp,"%s[%s]=%d\n",s1,s2,n);
          /*  puts(s); */
            break;
        default:
            sprintf(sp,"\n?Invalid format for debug() - %d\n",n);
         /*   puts(s); */
    }


 fprintf(dfp,s);

 return(0);
}


#endif

